package com.woniuxy.health.customer.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.woniuxy.health.customer.dto.UserDTO;
import com.woniuxy.health.customer.vo.UserVO;
import com.woniuxy.health.model.customer.User;
import com.woniuxy.health.utils.TokenUtil;
import com.woniuxy.utils.result.Asserts;
import com.woniuxy.utils.result.Result;
import com.woniuxy.utils.result.ResultCodeEnum;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import com.woniuxy.health.customer.service.IUserService;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author woniuxy
 * @since 2023-09-04
 */
@RestController
@CrossOrigin
@RequestMapping("/user")
public class UserController {



    private final IUserService userServiceImpl;
    private final RedisTemplate redisTemplate;
    public UserController(IUserService userServiceImpl, RedisTemplate redisTemplate){
        this.userServiceImpl = userServiceImpl;
        this.redisTemplate = redisTemplate;
    }


//    @GetMapping("info")
//    public Result getInfo(@RequestParam String token) {
//
//        Map<String, Object> map = new HashMap<>();
//        // map.put("token", "sdbafvjukyhgabvjha");
//        map.put("roles", "管理员");
//        map.put("name", "管理员");
//        map.put("avatar", "");
//        return Result.ok(map);
//    }
//    @PostMapping("login")
//    public Result login(@RequestBody UserDTO userDTO) {
//
//        Map<String, Object> map = new HashMap<>();
//        map.put("token", "sdbafvjukyhgabvjha");
//        return Result.ok(map);
//    }

    // private String getToken(User user) {
    //     //设置签名
    //     final JWTSigner signer = JWTSignerUtil.hs256(signature.getBytes());
    //     Map<String,Object> payload = new HashMap<>();
    //     //默认载荷
    //     payload.put("iss", "大健康");
    //     payload.put("iat", LocalDateTime.now());
    //     payload.put("userId", user.getId());
    //     payload.put("userName", user.getRealname());
    //     String token = JWTUtil.createToken(payload, signer);
    //     return token;
    // }

    @PostMapping("/login")
    public Result login(@RequestBody UserDTO userDTO, HttpServletRequest request){
        //1.根据账户名查询该用户是否存在
        User user = userServiceImpl.getOne(Wrappers.lambdaQuery(User.class).eq(User::getUsername, userDTO.getUsername()));
        Asserts.fail(Objects.isNull(user), ResultCodeEnum.ACCOUNT_PASSWORD_ERROR);

        //2.根据密码判断密码是否正确
        String md5Password = DigestUtils.md5DigestAsHex(userDTO.getLoginPwd().getBytes());
        Asserts.fail(!user.getLoginPwd().equals(md5Password),ResultCodeEnum.ACCOUNT_PASSWORD_ERROR);

        //3.登录成功将该id记录在redis中(set)
        //根据当天日期记录用户签到数量,使用bitmap
        redisTemplate.opsForValue().setBit("SignIn#".concat(LocalDate.now().plusDays(1).toString()),user.getId(),true);
        //根据当天日期记录用户登录状态,使用bitmap(登录时记录为1,退出时记录为0)
        redisTemplate.opsForValue().setBit("LoginStatus#".concat(LocalDate.now().toString()),user.getId(),true);

        //4.如果存在则代表登录成功则生成长短令牌
       // String accessToken = TokenUtil.createAccessToken(accessTime, user, signature, request);
        //String refreshToken = TokenUtil.createRefreshToken(refreshTime, user, signature, request);
        return  Result.ok(new UserVO(user.getId(),user.getNickname()));
    }

    /*获取当天的日活用户(默认当天)*/
    @GetMapping("/getActiveByDay")
    public Result getActiveByDay(){
        String key = "SignIn#".concat(LocalDate.now().toString());
        Long bitCount = 0L;
        if (redisTemplate.hasKey(key)){
            bitCount = getBitCount(key);
        }
        return Result.ok(bitCount);
    }

    /*获取当月的日活用户(默认当月)*/
    @GetMapping("/getActiveByMonth")
    public Result getActiveByMonth()
    {
        //获取当前月
        String format = LocalDate.now().format((DateTimeFormatter.ofPattern("yyyy-MM")));
        //从redis中寻找符合当前月的所有天数的key
        Set<String> keys = redisTemplate.keys("SignIn#".concat(format).concat("*"));
        System.out.println(keys.getClass());
        //不断地将key遍历并进行映射操作
        byte[][] bytes = keys.stream().map(String::getBytes).toArray(byte[][]::new);
        //key:前缀+月份
        String andResult = "CountByMonth#".concat(format);
        //默认情况下总数为0
        Long bitCount = 0L;
        if (keys.size() >= 2){
            redisTemplate.execute(
                    (RedisCallback) conn ->
                            conn.bitOp(RedisStringCommands.BitOperation.OR, andResult.getBytes(),bytes)
            );
            bitCount = getBitCount(andResult);
        }else if (keys.size() == 1){
            Object[] toArray = keys.toArray();
            //System.out.println(toArray[0].getClass());
            bitCount = getBitCount((String) toArray[0]);
        }
        //返回结果
        return Result.ok(bitCount);
    }

    /*统计各个时间段在线用户(定时器每天1个小时查询登录状态并记录下来,并以当天的日期+#LoginCount作为key存储)*/
    @GetMapping("/getCountByTime")
    public Result getCountByTime(){
        String key = "LoginCount#".concat(LocalDate.now().toString());
        //需要判断一下key是否为空
        if (redisTemplate.hasKey(key)){
            Map<String,Object> entries = redisTemplate.opsForHash().entries("LoginCount#".concat(LocalDate.now().toString()));
            return Result.ok(entries);
        }
        return Result.ok(0);
    }

    /*统计制定bitcount key的数量*/
    public Long getBitCount(String key){
        Long execute = (Long)redisTemplate.execute(
                (RedisCallback<Long>) connection ->
                        connection.bitCount(key.getBytes())
        );
        return execute;
    }

    //-------------------------------------------------------------//
    /*统计制定地区人数的数量*/
    @RequestMapping("/getLocationCount")
    public Result getLocationCount(){
        List<Map<String, Object>> mapList = userServiceImpl.listMaps(
                Wrappers.<User>query()
                        .select("user_location,count(*) as num")
                        .groupBy("user_location"));

        return Result.ok(mapList);
    }

    /*统计性别比例的数量*/
    @RequestMapping("/getGenderCount")
    public Result getGenderCount(){
        List<Map<String, Object>> mapList = userServiceImpl.listMaps(
                Wrappers.<User>query()
                        .select("user_gender,count(*) as num")
                        .groupBy("user_gender"));

        return Result.ok(mapList);
    }

    /*统计年龄分布的数量*/
    @RequestMapping("/getAgeCount")
    public Result getAgeCount(){
        List<Map<String,Integer>> result = userServiceImpl.getAgeCountList();
        return Result.ok(result);
    }


}
